﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BomberManServer.Gaming.Object;
using BomberManServer.Gaming.Socket;
using BomberManServer.Threading;
using BomberManServer.Gaming.Object.Mapping;
using BomberManServer.Gaming.Object.Mapping.Maps;
using BomberManServer.Gaming.Serialization;
using Stats = BomberManServer.Gaming.Object.Stats;
using BomberManServer.Utils;


namespace BomberManServer.Gaming
{
    public class Game
    {
        // the thread and port where that game will run
        public ThreadedSocket thread { get; private set; }
        public Match match { get; private set; }
        public Map map { get; set; }
        public ConnectionWatcher connections { get; private set; }
        public ActionListener listener { get; private set; }
        public ActionSender sender { get; private set; }
        public Time.Scheduler scheduler { get; private set; }
        public Serializer serializer { get; private set; }
        public MersenneTwister random { get; private set; }
        public uint seed { set { random.reset(value); } }
        public bool finished;

        public Logger.Thread logger { get; private set; }
        private Logger.Handler log;
        public Stats.GameStats stats { get; private set; }
        public RuleKeeper ruleKeeper { get; private set; }

        public Game(ThreadedSocket thread,Match match, Logger.Thread logger)
        {
            this.thread = thread;
            this.match = match;
            this.logger = logger;
            log = logger.createHandler("Game");

            foreach (Player player in match.players)
            {
                player.avatar.initialize(this);
            }

            scheduler = new Time.Scheduler();
            serializer = new Serializer();

            connections = new ConnectionWatcher(this);
            listener = new ActionListener(this);
            sender = new ActionSender(this);

            switch (match.type)
            {
                case Match.MatchType.FFA:
                    this.stats = new Stats.MeleeMatch.MeleeGameStats(match);
                    break;
                case Match.MatchType.TEAM:
                    this.stats = new Stats.TeamMatch.TeamGameStats(match);
                    break;
                case Match.MatchType.SOLO:
                    this.stats = new Stats.TeamMatch.TeamGameStats(match);
                    break;
            }
            
            this.ruleKeeper = new RuleKeeper(this);
            random = new MersenneTwister();
            finished = false;
        }

        //thread entry point
        public void start()
        {
            log.information("The game is starting");

            // instanciate the map
            switch (match.type)
            {
                case Match.MatchType.FFA:
                case Match.MatchType.TEAM:
                    map = new Melee(this);
                    break;
                case Match.MatchType.SOLO:
                    map = new Duel(this);
                    break;
            }

            // gaming thread main loop
            SynchronousPulsar pulsar = new SynchronousPulsar((uint)Constants.instance.actions_per_second);
            pulsar.action = new SynchronousPulsar.ActionHandler(main_loop);
            pulsar.idle = new SynchronousPulsar.TimeHandler(System.Threading.Thread.Sleep);
            pulsar.pulse();
        }

        private bool main_loop()
        {
            // check out connections
            connections.compute();
            // fetch new messages
            listener.read();
            // compute new round
            scheduler.compute();
            // send messages
            sender.compute();
            return !finished;
        }

    }
}
